{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# default_exp models.utils"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Models utils\n",
    "\n",
    "> Utility functions used to build PyTorch timeseries models."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#export\n",
    "from tsai.imports import *\n",
    "from tsai.models.layers import *\n",
    "from fastai.tabular.model import *\n",
    "from fastai.vision.models.all import *"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#export\n",
    "def get_layers(model, cond=noop, full=True):\n",
    "    if isinstance(model, Learner): model=model.model\n",
    "    if full: return [m for m in flatten_model(model) if any([c(m) for c in L(cond)])]\n",
    "    else: return [m for m in model if any([c(m) for c in L(cond)])]\n",
    "\n",
    "def is_layer(*args):\n",
    "    def _is_layer(l, cond=args):\n",
    "        return isinstance(l, cond)\n",
    "    return partial(_is_layer, cond=args)\n",
    "\n",
    "def is_linear(l):\n",
    "    return isinstance(l, nn.Linear)\n",
    "\n",
    "def is_bn(l):\n",
    "    types = (nn.BatchNorm1d, nn.BatchNorm2d, nn.BatchNorm3d)\n",
    "    return isinstance(l, types)\n",
    "\n",
    "def is_conv_linear(l):\n",
    "    types = (nn.Conv1d, nn.Conv2d, nn.Conv3d, nn.Linear)\n",
    "    return isinstance(l, types)\n",
    "\n",
    "def is_affine_layer(l):\n",
    "    return has_bias(l) or has_weight(l)\n",
    "\n",
    "def is_conv(l):\n",
    "    types = (nn.Conv1d, nn.Conv2d, nn.Conv3d)\n",
    "    return isinstance(l, types)\n",
    "\n",
    "def has_bias(l):\n",
    "    return (hasattr(l, 'bias') and l.bias is not None)\n",
    "\n",
    "def has_weight(l):\n",
    "    return (hasattr(l, 'weight'))\n",
    "\n",
    "def has_weight_or_bias(l):\n",
    "    return any((has_weight(l), has_bias(l)))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#export\n",
    "def check_bias(m, cond=noop, verbose=False):\n",
    "    mean, std = [], []\n",
    "    for i,l in enumerate(get_layers(m, cond=cond)): \n",
    "        if hasattr(l, 'bias') and l.bias is not None: \n",
    "            b = l.bias.data\n",
    "            mean.append(b.mean())\n",
    "            std.append(b.std())\n",
    "            pv(f'{i:3} {l.__class__.__name__:15} shape: {str(list(b.shape)):15}  mean: {b.mean():+6.3f}  std: {b.std():+6.3f}', verbose)\n",
    "    return np.array(mean), np.array(std)\n",
    "            \n",
    "def check_weight(m, cond=noop, verbose=False):\n",
    "    mean, std = [], []\n",
    "    for i,l in enumerate(get_layers(m, cond=cond)): \n",
    "        if hasattr(l, 'weight') and l.weight is not None: \n",
    "            w = l.weight.data\n",
    "            mean.append(w.mean())\n",
    "            std.append(w.std())\n",
    "            pv(f'{i:3} {l.__class__.__name__:15} shape: {str(list(w.shape)):15}  mean: {w.mean():+6.3f}  std: {w.std():+6.3f}', verbose)\n",
    "    return np.array(mean), np.array(std)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#export\n",
    "def get_nf(m):\n",
    "    \"Get nf from model's first linear layer in head\"\n",
    "    return get_layers(m[-1], is_linear)[0].in_features"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#export\n",
    "def ts_splitter(m):\n",
    "    \"Split of a model between body and head\"\n",
    "    return L(m.backbone, m.head).map(params)\n",
    "\n",
    "\n",
    "def transfer_weights(model, weights_path:Path, device:torch.device=None, exclude_head:bool=True):\n",
    "    \"\"\"Utility function that allows to easily transfer weights between models.\n",
    "    Taken from the great self-supervised repository created by Kerem Turgutlu.\n",
    "    https://github.com/KeremTurgutlu/self_supervised/blob/d87ebd9b4961c7da0efd6073c42782bbc61aaa2e/self_supervised/utils.py\"\"\"\n",
    "\n",
    "    device = ifnone(device, default_device())\n",
    "    state_dict = model.state_dict()\n",
    "    new_state_dict = torch.load(weights_path, map_location=device)\n",
    "    matched_layers = 0\n",
    "    unmatched_layers = []\n",
    "    for name, param in state_dict.items():\n",
    "        if exclude_head and 'head' in name: continue\n",
    "        if name in new_state_dict:\n",
    "            matched_layers += 1\n",
    "            input_param = new_state_dict[name]\n",
    "            if input_param.shape == param.shape: param.copy_(input_param)\n",
    "            else: unmatched_layers.append(name)\n",
    "        else:\n",
    "            unmatched_layers.append(name)\n",
    "            pass # these are weights that weren't in the original model, such as a new head\n",
    "    if matched_layers == 0: raise Exception(\"No shared weight names were found between the models\")\n",
    "    else:\n",
    "        if len(unmatched_layers) > 0:\n",
    "            print(f'check unmatched_layers: {unmatched_layers}')\n",
    "        else:\n",
    "            print(f\"weights from {weights_path} successfully transferred!\\n\")\n",
    "        \n",
    "        \n",
    "def build_ts_model(arch, c_in=None, c_out=None, seq_len=None, d=None, dls=None, device=None, verbose=False, \n",
    "                   pretrained=False, weights_path=None, exclude_head=True, cut=-1, init=None, arch_config={}, **kwargs):\n",
    "\n",
    "    device = ifnone(device, default_device())\n",
    "    if dls is not None:\n",
    "        c_in = ifnone(c_in, dls.vars)\n",
    "        c_out = ifnone(c_out, dls.c)\n",
    "        seq_len = ifnone(seq_len, dls.len)\n",
    "        d = ifnone(d, dls.d)\n",
    "    if is_listy(d) and len(d) == 2:\n",
    "        if 'custom_head' not in kwargs.keys(): \n",
    "            kwargs['custom_head'] = partial(lin_3d_head, d=d)\n",
    "        else:\n",
    "            kwargs['custom_head'] = partial(kwargs['custom_head'], d=d)\n",
    "    if sum([1 for v in ['RNN_FCN', 'LSTM_FCN', 'RNNPlus', 'LSTMPlus', 'GRUPlus', 'InceptionTime', 'TSiT',\n",
    "                        'GRU_FCN', 'OmniScaleCNN', 'mWDN', 'TST', 'XCM', 'MLP', 'MiniRocket', 'InceptionRocket']\n",
    "            if v in arch.__name__]):\n",
    "        pv(f'arch: {arch.__name__}(c_in={c_in} c_out={c_out} seq_len={seq_len} device={device}, arch_config={arch_config}, kwargs={kwargs})', verbose)\n",
    "        model = arch(c_in, c_out, seq_len=seq_len, **arch_config, **kwargs).to(device=device)\n",
    "    elif 'xresnet' in arch.__name__ and not '1d' in arch.__name__:\n",
    "        pv(f'arch: {arch.__name__}(c_in={c_in} c_out={c_out} device={device}, arch_config={arch_config}, kwargs={kwargs})', verbose)\n",
    "        model = (arch(c_in=c_in, n_out=c_out, **arch_config, **kwargs)).to(device=device)\n",
    "    elif 'minirockethead' in arch.__name__.lower():\n",
    "        pv(f'arch: {arch.__name__}(c_in={c_in} seq_len={seq_len} device={device}, arch_config={arch_config}, kwargs={kwargs})', verbose)\n",
    "        model = (arch(c_in, c_out, seq_len=1, **arch_config, **kwargs)).to(device=device)\n",
    "    elif 'rocket' in arch.__name__.lower():\n",
    "        pv(f'arch: {arch.__name__}(c_in={c_in} seq_len={seq_len} device={device}, arch_config={arch_config}, kwargs={kwargs})', verbose)\n",
    "        model = (arch(c_in=c_in, seq_len=seq_len, **arch_config, **kwargs)).to(device=device)\n",
    "    else:\n",
    "        pv(f'arch: {arch.__name__}(c_in={c_in} c_out={c_out} device={device}, arch_config={arch_config}, kwargs={kwargs})', verbose)\n",
    "        model = arch(c_in, c_out, **arch_config, **kwargs).to(device=device)\n",
    "\n",
    "    try:\n",
    "        model[0], model[1]\n",
    "        subscriptable = True\n",
    "    except:\n",
    "        subscriptable = False\n",
    "    if hasattr(model, \"head_nf\"):  head_nf = model.head_nf\n",
    "    else:\n",
    "        try: head_nf = get_nf(model)\n",
    "        except: head_nf = None\n",
    "\n",
    "    if not subscriptable and 'Plus' in arch.__name__:\n",
    "        model = nn.Sequential(*model.children())\n",
    "        model.backbone = model[:cut]\n",
    "        model.head = model[cut:]\n",
    "\n",
    "    if pretrained and not ('xresnet' in arch.__name__ and not '1d' in arch.__name__):\n",
    "        assert weights_path is not None, \"you need to pass a valid weights_path to use a pre-trained model\"\n",
    "        transfer_weights(model, weights_path, exclude_head=exclude_head, device=device)\n",
    "\n",
    "    if init is not None:\n",
    "        apply_init(model[1] if pretrained else model, init)\n",
    "\n",
    "    setattr(model, \"head_nf\", head_nf)\n",
    "    setattr(model, \"__name__\", arch.__name__)\n",
    "\n",
    "    return model\n",
    "    \n",
    "build_model = build_ts_model\n",
    "create_model = build_ts_model\n",
    "    \n",
    "    \n",
    "@delegates(TabularModel.__init__)\n",
    "def build_tabular_model(arch, dls, layers=None, emb_szs=None, n_out=None, y_range=None, device=None, arch_config={}, **kwargs):\n",
    "    if device is None: device = default_device()\n",
    "    if layers is None: layers = [200,100]\n",
    "    emb_szs = get_emb_sz(dls.train_ds, {} if emb_szs is None else emb_szs)\n",
    "    if n_out is None: n_out = get_c(dls)\n",
    "    assert n_out, \"`n_out` is not defined, and could not be inferred from data, set `dls.c` or pass `n_out`\"\n",
    "    if y_range is None and 'y_range' in kwargs: y_range = kwargs.pop('y_range')\n",
    "    model = arch(emb_szs, len(dls.cont_names), n_out, layers, y_range=y_range, **arch_config, **kwargs).to(device=device)\n",
    "    \n",
    "    if hasattr(model, \"head_nf\"):  head_nf = model.head_nf\n",
    "    else: head_nf = get_nf(model)\n",
    "    setattr(model, \"__name__\", arch.__name__)\n",
    "    if head_nf is not None: setattr(model, \"head_nf\", head_nf)\n",
    "    return model\n",
    "\n",
    "create_tabular_model = build_tabular_model\n",
    "\n",
    "\n",
    "@delegates(XResNet.__init__)\n",
    "def build_tsimage_model(arch, c_in=None, c_out=None, dls=None, pretrained=False, device=None, verbose=False, init=None, arch_config={}, **kwargs):\n",
    "    device = ifnone(device, default_device())\n",
    "    if dls is not None:\n",
    "        c_in = ifnone(c_in, dls.vars)\n",
    "        c_out = ifnone(c_out, dls.c)\n",
    "    \n",
    "    model = arch(pretrained=pretrained, c_in=c_in, n_out=c_out, **arch_config, **kwargs).to(device=device)\n",
    "    setattr(model, \"__name__\", arch.__name__)\n",
    "    if init is not None: \n",
    "        apply_init(model[1] if pretrained else model, init)\n",
    "    return model\n",
    "    \n",
    "\n",
    "def count_parameters(model, trainable=True):\n",
    "    if trainable: return sum(p.numel() for p in model.parameters() if p.requires_grad)\n",
    "    else: return sum(p.numel() for p in model.parameters())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Feature Extraction: 100%|██████████| 40/40 [00:04<00:00,  8.83it/s]\n"
     ]
    }
   ],
   "source": [
    "from tsai.data.external import get_UCR_data\n",
    "from tsai.data.features import get_ts_features\n",
    "dsid = 'NATOPS'\n",
    "X, y, splits = get_UCR_data(dsid, split_data=False)\n",
    "ts_features_df = get_ts_features(X, y)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from tsai.data.tabular import get_tabular_dls\n",
    "from tsai.models.TabModel import TabModel\n",
    "cat_names = None\n",
    "cont_names = ts_features_df.columns[:-2]\n",
    "y_names = 'target'\n",
    "tab_dls = get_tabular_dls(ts_features_df, cat_names=cat_names, cont_names=cont_names, y_names=y_names, splits=splits)\n",
    "tab_model = build_tabular_model(TabModel, dls=tab_dls)\n",
    "b = first(tab_dls.train)\n",
    "test_eq(tab_model(*b[:-1]).shape, (64,6))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1\n"
     ]
    }
   ],
   "source": [
    "a = 'MLSTM_FCN'\n",
    "if sum([1 for v in ['RNN_FCN', 'LSTM_FCN', 'GRU_FCN', 'OmniScaleCNN', 'Transformer', 'mWDN'] if v in a]): print(1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#export\n",
    "def get_clones(module, N):\n",
    "    return nn.ModuleList([deepcopy(module) for i in range(N)])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "ModuleList(\n",
       "  (0): Conv1d(3, 4, kernel_size=(3,), stride=(1,))\n",
       "  (1): Conv1d(3, 4, kernel_size=(3,), stride=(1,))\n",
       "  (2): Conv1d(3, 4, kernel_size=(3,), stride=(1,))\n",
       ")"
      ]
     },
     "execution_count": null,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "m = nn.Conv1d(3,4,3)\n",
    "get_clones(m, 3)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#export\n",
    "def split_model(m): return m.backbone, m.head"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#export\n",
    "@torch.no_grad()\n",
    "def output_size_calculator(m, c_in, seq_len):\n",
    "    try: device = list(m.parameters())[0].device\n",
    "    except: device = None\n",
    "    xb = torch.randn(1, c_in, seq_len, device=device)\n",
    "    c_in, seq_len = m(xb).shape[1:]\n",
    "    return c_in, seq_len"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "c_in = 3\n",
    "seq_len = 30\n",
    "m = nn.Conv1d(3, 12, kernel_size=3, stride=2)\n",
    "new_c_in, new_seq_len = output_size_calculator(m, c_in, seq_len)\n",
    "test_eq((new_c_in, new_seq_len), (12, 14))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#export\n",
    "def change_model_head(model, custom_head, **kwargs):\n",
    "    r\"\"\"Replaces a model's head by a custom head as long as the model has a head, head_nf, c_out and seq_len attributes\"\"\"\n",
    "    model.head = custom_head(model.head_nf, model.c_out, model.seq_len, **kwargs)\n",
    "    return model"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# export\n",
    "def naive_forecaster(o, split, horizon=1):\n",
    "    if is_listy(horizon):\n",
    "        _f = []\n",
    "        for h in horizon:\n",
    "            _f.append(o[np.asarray(split)-h])\n",
    "        return np.stack(_f)\n",
    "    return o[np.asarray(split) - horizon]\n",
    "\n",
    "def true_forecaster(o, split, horizon=1):\n",
    "    o_true = o[split]\n",
    "    if is_listy(horizon): \n",
    "        o_true = o_true[np.newaxis].repeat(len(horizon), 0)\n",
    "    return o_true"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(array([0.59869925, 0.74718208, 1.08105135, 1.4689609 , 1.6832443 ,\n",
       "        2.06999004, 2.59478098, 3.45776211, 4.42666347, 4.54807169,\n",
       "        4.95395324, 5.42060075, 6.28736975, 6.40664888, 6.69426184,\n",
       "        7.63565696, 7.73916016, 8.2447472 , 9.06291453, 9.28543749]),\n",
       " array([4.54807169, 4.95395324, 5.42060075, 6.28736975, 6.40664888,\n",
       "        6.69426184, 7.63565696, 7.73916016, 8.2447472 , 9.06291453]),\n",
       " array([4.95395324, 5.42060075, 6.28736975, 6.40664888, 6.69426184,\n",
       "        7.63565696, 7.73916016, 8.2447472 , 9.06291453, 9.28543749]))"
      ]
     },
     "execution_count": null,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "a = np.random.rand(20).cumsum()\n",
    "split = np.arange(10, 20)\n",
    "a, naive_forecaster(a, split, 1), true_forecaster(a, split, 1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/javascript": [
       "IPython.notebook.save_checkpoint();"
      ],
      "text/plain": [
       "<IPython.core.display.Javascript object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "100b_models.utils.ipynb saved at 2021-11-24 13:33:51.\n",
      "Converted 100b_models.utils.ipynb.\n",
      "\n",
      "\n",
      "Correct conversion! 😃\n",
      "Total time elapsed 0.091 s\n",
      "Wednesday 24/11/21 13:33:54 CET\n"
     ]
    },
    {
     "data": {
      "text/html": [
       "\n",
       "                <audio  controls=\"controls\" autoplay=\"autoplay\">\n",
       "                    <source src=\"data:audio/wav;base64,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\" type=\"audio/wav\" />\n",
       "                    Your browser does not support the audio element.\n",
       "                </audio>\n",
       "              "
      ],
      "text/plain": [
       "<IPython.lib.display.Audio object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "#hide\n",
    "from tsai.imports import create_scripts\n",
    "from tsai.export import get_nb_name\n",
    "nb_name = get_nb_name()\n",
    "create_scripts(nb_name);"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
